﻿using System;
using System.ComponentModel;
using System.Runtime.Serialization;
using Core.Helper;

namespace Core.Model
{

    [DataContract]
    public class DataItem:INotifyPropertyChanged
    {
        // not store in db
        public event PropertyChangedEventHandler PropertyChanged;

        #region field

        private string _id;

        private string _name;

        private int _address;

        private Access _access;

        private string _deviceId;

        private PhyType _phyType = PhyType.模拟量;

        private DataType _dataType = DataType.Int32;

        private Category _category = Category.即时值;

        private int _triggerValue = 1;

        private bool _isStorage;

        private int _storageCycle = 5;

        private string _subInfo;

        private Extra _tagObject;

        private object _value;

        private double _curValue;

        private DateTime _updateTime;

        //private DateTime postTime = DateTime.Now;
        #endregion

        #region property
        [DisplayName("唯一ID")]
        [Browsable(false)]
        [DataMember]
        public string Id
        {
            get => _id;
            set
            {
                if (_id != value)
                {
                    _id = value;
                    NotifyPropertyChanged("Id");
                }
            }
        }
        [DisplayName("数据名称")]
        [DataMember]
        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    NotifyPropertyChanged("Name");
                }
            }
        }
        [ReadOnly(true)]
        [DisplayName("数据序号")]
        [DataMember]
        public int Position { get; set; }
        [DisplayName("数据地址")]
        //[DataMember]
        public int Address
        {
            get => _address;
            set
            {
                if (_address != value)
                {
                    _address = value;
                    NotifyPropertyChanged("Address");
                }
            }
        }
        [DisplayName("权限")]
        [DataMember]
        public Access Access
        {
            get => _access;
            set
            {
                if (_access != value)
                {
                    _access = value;
                    NotifyPropertyChanged("Access");
                }
            }
        }
        [ReadOnly(true)]
        [DisplayName("设备ID")]
        [DataMember]
        public string DeviceId
        {
            get => _deviceId;
            set
            {
                if (_deviceId != value)
                {
                    _deviceId = value;
                    NotifyPropertyChanged("DeviceId");
                }
            }
        }
        [DisplayName("物理归类")]
        [DataMember]
        public PhyType PhyType
        {
            get => _phyType;
            set
            {
                if (_phyType != value)
                {
                    _phyType = value;
                    NotifyPropertyChanged("PhyType");
                }
            }
        }
        [DisplayName("数值类型")]
        //[DataMember]
        public DataType DataType
        {
            get => _dataType;
            set
            {
                if (_dataType != value)
                {
                    _dataType = value;
                    NotifyPropertyChanged("DataType");
                }
            }
        }
        [DisplayName("应用类型")]
        [DataMember]
        public Category Category
        {
            get => _category;
            set
            {
                if (_category != value)
                {
                    _category = value;
                    NotifyPropertyChanged("Category");
                }
            }
        }
        [DisplayName("信号触发值")]
        [DataMember]
        public  int TriggerValue
        {
            get => _triggerValue;
            set
            {
                if (_triggerValue != value)
                {
                    _triggerValue = value;
                    NotifyPropertyChanged("TriggerValue");
                }
            }
        }
        [DisplayName("存储否")]
        //[DataMember]
        public bool IsStorage
        {
            get => _isStorage;
            set
            {
                if (_isStorage != value)
                {
                    _isStorage = value;
                    NotifyPropertyChanged("IsStorage");
                }
            }
        }
        [DisplayName("存储周期")]
        //[DataMember]
        public int StorageCycle
        {
            get => _storageCycle;
            set
            {
                if (_storageCycle != value)
                {
                    _storageCycle = value;
                    NotifyPropertyChanged("StorageCycle");
                }
            }
        }
        /// <summary>
        /// 附加信息，由TagObject转Json而来，用于存储到数据库
        /// </summary>
        [Browsable(false)]
        //[DataMember]
        public string SubInfo
        {
            get => _subInfo;
            set
            {
                if (_subInfo != value)
                {
                    _subInfo = value;
                    NotifyPropertyChanged("SubInfo");
                }
            }
        }
        /// <summary>
        /// 附加信息，若无可不处理
        /// </summary>
        [DisplayName("附加属性")]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public Extra TagObject
        {
            get => _tagObject;
            set => _tagObject = value;
        }
        [ReadOnly(true)]
        [DisplayName("当前值")]
        public object Value
        {
            get => _value;
            set
            {
                if (_value != value)
                {
                    _value = value;
                    try
                    {
                        if (PhyType == PhyType.信号量)
                        {
                            //postTime = DateTime.Now;
                            Global.DataAccess.PostData(Id, true, _value,TriggerValue);
                        }
                        else
                        {
                            //if ((DateTime.Now - postTime).Milliseconds > Global.DataAccess.UpdateInterval || _curValue==0)
                            //{
                                //postTime = DateTime.Now;
                                Global.DataAccess.PostData(Id,false , _value);
                            //}
                        }
                        NotifyPropertyChanged("Value");
                    }
                    catch
                    {
                    }
                }
            }
        }
        [ReadOnly(true)]
        [DisplayName("当前数值")]
        public double CurValue
        {
            get => _curValue;
            set
            {
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (value != _curValue)
                {
                    _curValue = value;
                    Value = _curValue;
                    NotifyPropertyChanged("CurValue");
                }
                else
                {
                    if (Value == null)
                    {
                        Value = _curValue;
                    }
                }
                UpdateTime = DateTime.Now;
            }
        }
        [ReadOnly(true)]
        [DisplayName("更新时间")]
        public DateTime UpdateTime
        {
            get => _updateTime;
            set
            {
                if (_updateTime != value)
                {
                    _updateTime = value;
                    NotifyPropertyChanged("UpdateTime");
                }
            }
        }

        [ReadOnly(true)]
        [DisplayName("最后存储时间")]
        public DateTime LastStoreTime { get; set; } = DateTime.Now.AddSeconds(-50);
        #endregion

        public DataItem()
        {
            this.Id = IdHelper.GuidToString();
        }

        public DataItem(string name,string devId)
        {
            this.Id = IdHelper.GuidToString();
            this.Name = name;
            this.DeviceId = devId;
        }
        // 注意不是简单复制，Name,Position，Address  可能会改变
        public DataItem(DataItem src)
        {
            this.Id = IdHelper.GuidToString();
            this.Name = "新数据项";
            this.DeviceId = src.DeviceId;
            this.Access = src.Access;
            this.Category = src.Category;
            this.TriggerValue = src.TriggerValue;
            this.IsStorage = src.IsStorage;
            this.StorageCycle = src.StorageCycle;
            this.PhyType = src.PhyType;
            this.Position = src.Position + 1;
            this.TagObject = src.TagObject;
            this.DataType = src.DataType;
            
            switch (this.DataType)
            {
                case DataType.Byte:
                case DataType.Sbyte:
                    this.Address = src.Address;
                    break;
                case DataType.Int16:
                case DataType.UInt16:
                case DataType.BCD2:
                    this.Address = src.Address + 1;
                    break;
                case DataType.Int32:
                case DataType.UInt32:
                case DataType.Single:
                case DataType.BCD4:
                    this.Address = src.Address + 2;
                    break;
                case DataType.Int64:
                case DataType.UInt64:
                case DataType.Double:
                    this.Address = src.Address + 4;
                    break;
                default:
                    this.Address = src.Address + 1;
                    break;
            }
        }

        public DataItem Clone(string newId,string devId)
        {
            DataItem dataItem = new DataItem();
            dataItem.Id = newId;
            dataItem.Name = Name;
            dataItem.Access = Access;
            dataItem.Address = Address;
            dataItem.Category = Category;
            dataItem.DataType = DataType;
            dataItem.IsStorage = IsStorage;
            dataItem.DeviceId = devId;
            dataItem.PhyType = PhyType;
            dataItem.Position = Position;
            dataItem.StorageCycle = StorageCycle;
            dataItem.SubInfo = SubInfo;
            dataItem.TriggerValue = TriggerValue;
            return dataItem;
        }
        protected void NotifyPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(name));
        }
       
        public int GetDataLength()
        {
            int len;
            switch (this.DataType)
            {
                case DataType.Byte:
                case DataType.Sbyte:
                    len = 1;
                    break;
                case DataType.Int16:
                case DataType.UInt16:
                case DataType.BCD2:
                    len = 2;
                    break;
                case DataType.Int32:
                case DataType.UInt32:
                case DataType.Single:
                case DataType.BCD4:
                    len = 4;
                    break;
                case DataType.Int64:
                case DataType.UInt64:
                case DataType.Double:
                    len = 8;
                    break;
                default:
                    len = 2;
                    break;
            }
            return len;
        }

        public override string ToString()
        {
            return this.Name;
        }
    }

    [DataContract]
    public enum PhyType
    {
        [EnumMember]
        模拟量 =0,
        [EnumMember]
        信号量 =1
    }

    [DataContract]
    public enum Category
    {
        [Description("即时值")]
        [EnumMember]
        即时值 = 0,
        [Description("累加值")]
        [EnumMember]
        累加值 = 1,
        [Description("在分区域报表中设备默认查询的数据项")]
        [EnumMember]
        报表值 = 2,
    }
    [DataContract]
    public enum Access
    {
        [Description("只读")]
        [EnumMember]
        只读 = 0,
        [Description("只写")]
        [EnumMember]
        只写 = 1,
        [Description("可读可写")]
        [EnumMember]
        读写 = 2
    }
    [DataContract]
    public enum DataType
    {
        /// <summary>
        /// 无符号字节
        /// </summary>
        [EnumMember]
        Byte = 0,
        /// <summary>
        /// 有符号字节
        /// </summary>
        [EnumMember]
        Sbyte,
        /// <summary>
        /// 有符号短整型
        /// </summary>
        [EnumMember]
        Int16,
        /// <summary>
        /// 无符号短整型
        /// </summary>
        [EnumMember]
        UInt16,
        /// <summary>
        /// 有符号整型
        /// </summary>
        [EnumMember]
        Int32,
        /// <summary>
        /// 无符号整型
        /// </summary>
        [EnumMember]
        UInt32,
        /// <summary>
        /// 单精度浮点型
        /// </summary>
        [EnumMember]
        Single,
        /// <summary>
        /// 双精度浮点型（8字节）
        /// </summary>
        [EnumMember]
        Double,
        /// <summary>
        /// 8字节有符号长整型
        /// </summary>
        [EnumMember]
        Int64,
        /// <summary>
        /// 8字节无符号长整型
        /// </summary>
        [EnumMember]
        UInt64,
        /// <summary>
        /// 2字节压缩BCD码
        /// </summary>
        [EnumMember]
        BCD2,
        /// <summary>
        /// 4字节压缩BCD码
        /// </summary>
        [EnumMember]
        BCD4,
        /// <summary>
        /// 字节数组
        /// </summary>
        [EnumMember]
        Bytes,
        /// <summary>
        /// 字符串
        /// </summary>
        [EnumMember]
        String
    }

    public class Extra
    {
        public virtual string Serialize()
        {
            return "";
        }
    }
   
}
